home *** CD-ROM | disk | FTP | other *** search
- /* history -- command history mechanism, Copyright 1985-6 Michael M Rubenstein */
- /* Portions Copyright 1987, 1988, Russell Nelson */
- /* History:19,1 */
- /* 01-29-88 19:59:01 add C-A and C-E for home and end respectively. */
- /* 10-18-87 12:12:06 give an error if they compile with other than TINY. */
- /* 10-18-87 11:51:06 use msdos(8) to read keystrokes. */
- /* 07-05-87 13:57:09 lowercase filenames properly this time. */
- /* 07-04-87 23:49:11 don't do an automatic search. */
- /* 07-03-87 22:07:56 Use '\0' for the null character. */
- /* 07-03-87 21:22:23 expand_filename didn't put a trailing \ after directories. */
- /* 07-03-87 21:03:57 filename expansion didn't check 'len'. */
- /* 07-03-87 19:42:20 in filename completion, files with wildcards don't get wildcards added */
- /* 07-03-87 19:36:31 move argc, argv code out of history_init() */
- /* 07-03-87 15:49:27 change copyright message */
-
- #include <ctype.h>
- #include <dos.h>
- #include <dir.h>
-
- #define FALSE 0
- #define TRUE 1
- #define NULL ((void *) 0)
-
- /* some interesting characters */
- #define CTL 0x1f
- #define NUL 0
- #define CTLA (CTL & 'A')
- #define CTLB (CTL & 'B')
- #define CTLD (CTL & 'D')
- #define CTLE (CTL & 'E')
- #define CTLF (CTL & 'F')
- #define BEL (CTL & 'G')
- #define BS (CTL & 'H')
- #define LF (CTL & 'J')
- #define CR (CTL & 'M')
- #define CTLL (CTL & 'L')
- #define CTLQ (CTL & 'Q')
- #define CTLT (CTL & 'T')
- #define CTLU (CTL & 'U')
- #define CTLW (CTL & 'W')
- #define CTLX (CTL & 'X')
- #define CTLY (CTL & 'Y')
- #define ESC (CTL & '[')
- #define STATUS (CTL & ']')
- #define DEL 0x7f
-
- /* extended characters */
- #define F1 256 + 59
- #define F2 256 + 60
- #define F3 256 + 61
- #define F4 256 + 62
- #define F5 256 + 63
- #define F6 256 + 64
- #define F7 256 + 65
- #define F8 256 + 66
- #define F9 256 + 67
- #define F10 256 + 68
- #define HOME 256 + 71
- #define UP 256 + 72
- #define LEFT 256 + 75
- #define RIGHT 256 + 77
- #define END 256 + 79
- #define DOWN 256 + 80
- #define INS 256 + 82
- #define KDEL 256 + 83
- #define CTLLEFT 256 + 115
- #define CTLRIGHT 256 + 116
-
- int insert = FALSE; /* insert mode switch */
- unsigned char line[256];
-
- unsigned lineoff, lineseg; /* offset and seg of line */
- unsigned char *cur; /* current position in line */
- int len; /* max length of line */
- unsigned startpos, endpos, prevpos; /* screen positions */
- int vpage, /* video page */
- maxcols, /* cols on screen */
- cursor, /* standard cursor */
- icursor; /* insert cursor */
-
- extern void setup();
-
- #ifndef __TINY__
- #error Must be compiled with -mt
- #endif
-
- void exit(int c)
- { _exit(c);}
-
- void _setenvp(void){} /* dummy out _setenvp */
-
- void main(int argc, char *argv[])
- {
-
- unsigned len, j;
-
- --argc;
- for (j = 0; j <= 1; j++) {
- if (argc) {
- argc--;
- if ((len = atoi(*argv++)) < 256) len = 256;
- else if (len > 32767) len = 32767;
- }
- else len = 256;
- init_history(j, len);
- }
- setup();
- }
-
-
- /* get a line with editing & history */
- getline()
- {
- int c;
- unsigned char *p;
- static unsigned oldseg = 0;
-
-
- /* the first time we're called it's from COMMAND.COM. Save the segment */
- /* so we can recognize calls from COMMAND.COM. */
- if (oldseg == 0) {
- oldseg = lineseg;
- }
-
- select_history( (lineseg == oldseg) ? 0 : 1);
-
- /* set up for input */
- len = peekb(lineseg, lineoff) & 0xff;
- memset(cur = line, 0, len);
- insert = FALSE;
- init_pos();
- getvpage();
- reset_history();
-
- /* main editing loop */
- for (;;)
- {
- c = getcon();
-
- switch (c)
- {
- case CR: /* done with line */
- setcursor(cursor);
- putch('\r');
- setpos(endpos);
- if (line[0] != '\0')
- puthist();
- storeline();
- return;
-
- case STATUS: /* type out some info */
- cur = line;
- init_pos();
- showln();
- break;
-
- case LF: /* expand filenames */
- findfiles();
- break;
-
- case CTLB:
- case LEFT: /* back one character */
- if (cur != line)
- backup();
- break;
-
- case CTLLEFT: /* back one word */
- backwd();
- break;
-
- case CTLRIGHT:
- /* forward one word */
- while (isalnum(*cur))
- forward();
- while (*cur != 0 && !isalnum(*cur))
- forward();
- break;
-
- case DEL:
- case BS: /* backspace and delete */
- if (cur == line)
- break;
- backup(); /* NOTE fall through */
-
- case CTLD:
- case KDEL: /* delete current char */
- if (*cur != '\0')
- delchr();
- break;
-
- case CTLW:
- case F9: /* delete word left */
- backwd();
- /* NOTE fall through */
- case CTLT:
- case F10: /* delete word right */
- while (isalnum(*cur))
- delchr();
- while (*cur != 0 && !isalnum(*cur))
- delchr();
- break;
-
- /* get pattern if at beginning else forward */
- case F1: if (cur == line && line[0] == '\0')
- {
- getpat();
- break;
- }
- case CTLF:
- case RIGHT: /* forward one character */
- if (*cur != 0)
- forward();
- break;
-
- case INS: /* insert char */
- insert = !insert;
- setcursor(insert? icursor : cursor);
- break;
-
- case CTLU:
- case CTLX:
- case ESC: /* delete line */
- delln();
- reset_history();
- break;
-
- case CTLY:
- case F8: /* delete to end of line */
- while (*cur != 0)
- delchr();
- break;
-
- case CTLA:
- case HOME: home();
- break;
-
- case F3: getpat();
- case CTLE:
- case END: while (*cur != 0)
- forward();
- break;
-
- case UP: prevhist();
- break;
-
- case DOWN: nexthist();
- break;
-
- case CTLL:
- case F7: search();
- break;
-
- case NUL: /* ignore nulls */
- break;
-
- case F2: getpat();
- c = getcon();
- if (*cur == '\0')
- break;
- for (p = cur + 1; *p != '\0' && *p != c; ++p)
- ;
- if (*p != '\0')
- while (cur < p)
- forward();
- break;
-
- case F4: getpat();
- c = getcon();
- if (*cur == '\0')
- break;
- for (p = cur + 1; *p != '\0'&& *p != c; ++p)
- ;
- if (*p != '\0')
- while (*cur != c)
- delchr();
- break;
-
- case F5: storeline();
- break;
-
- case F6:
- case CTLQ: c = getcon();
- if (c >= 256) break;
- /* NOTE fall through */
- default: if (c > 255)
- continue;
- if (cur - line == len - 1)
- bell();
- else
- {
- if (insert)
- inschr();
- *cur = c;
- forward();
- showln();
- #ifdef SEARCH
- search();
- #endif
- }
- }
- }
- }
-
- /* get extended character from console */
- getcon()
- {
- int c;
-
- _AH = 8;
- geninterrupt(0x21);
- c = _AL;
- if (c == '\0' && kbhit()) {
- _AH = 8;
- geninterrupt(0x21);
- c = _AL;
- c += 256;
- }
- return c;
- }
-
- /* get pattern from line buffer */
- getpat()
- {
- int i, n;
-
- if (cur == line && line[0] == '\0')
- {
- for (i = 0, n = peekb(lineseg, lineoff + 1) & 0xff; i < n; ++i)
- line[i] = peekb(lineseg, lineoff + 2 + i);
- line[i] = '\0';
- home();
- showln();
- }
- }
-
- /* store the line */
- storeline()
- {
- register unsigned char
- *p;
- register int i;
-
- for (i = 0, p = line; *p != '\0'; ++i, ++p)
- pokeb(lineseg, lineoff + 2 + i, *p);
- pokeb(lineseg, lineoff + 2 + i, CR);
- pokeb(lineseg, lineoff + 1, i);
- }
-
- /* back one word */
- backwd()
- {
- if (cur == line)
- return;
- backup();
- while (cur != line && !isalnum(*cur))
- backup();
- while (cur != line && isalnum(*(cur - 1)))
- backup();
- }
-
- /* delete character */
- delchr()
- {
- unsigned char *p;
- unsigned pos;
-
- pos = getpos();
-
- for (p = cur; (*p = *(p + 1)) != '\0'; ++p)
- pctl(*p);
-
- pctl(' ');
- pctl(' ');
- setpos(pos);
- }
-
- /* insert a character in line */
- inschr(void)
- {
- unsigned char *p;
-
- for (p = cur; *p != '\0'; ++p)
- ;
- if (p > line + len - 2)
- p = line + len - 2;
-
- *(p + 1) = '\0';
-
- while (p > cur)
- {
- *p = *(p - 1);
- --p;
- }
- *cur = ' ';
- }
-
- /* delete entire line */
- delln(void)
- {
- home();
- while (*cur != '\0')
- {
- if (*cur < ' ' || *cur == DEL)
- putch(' ');
- putch(' ');
- ++cur;
- }
- home();
- init_pos();
- memset(cur = line, 0, len);
- }
-
- /* move cursor to start of line */
- home(void)
- {
- cur = line;
- setpos(startpos);
- }
-
- /* show line from current position */
- showln(void)
- {
- unsigned char *p;
-
- if (*cur != 0)
- {
- p = cur;
- while (*cur != '\0')
- forward();
- home();
- while (cur < p)
- forward();
- }
- }
-
- /* back up one character */
- backup(void)
- {
- unsigned pos;
- int row, col;
-
- --cur;
- pos = getpos();
- row = (pos >> 8) & 0xff;
- col = pos & 0xff;
- col -= (*cur < ' ' || *cur == DEL) ? 2 : 1;
- if (col < 0)
- {
- --row;
- col = 79;
- }
- setpos((row << 8) + col);
- }
-
- /* forward one character */
- forward(void)
- {
- pctl(*(cur++));
- }
-
- /* insert a printable character */
- insprintable(char c)
- {
- if (cur - line == len - 1) return;
- inschr();
- *cur = c;
- forward();
- }
-
-
- findfiles(void)
- {
- struct ffblk ourFF;
- char far *oldDta;
- char *oldCur, *scur;
- char findname[64];
- char *fn1, *fn2;
- int foundChars;
- int j;
-
- if (cur == line)
- return;
-
- /* get the word to the left of the cursor into findname */
- oldCur = cur;
- for (;;) {
- if (cur == line) break;
- backup();
- if (isspace(*cur)) {
- forward();
- break;
- }
- }
-
- scur = cur;
- fn1 = fn2 = findname;
- foundChars = 0;
- while (scur != oldCur) {
- switch(*fn1++ = *scur++) {
- case '.': /* remember if it has extension */
- foundChars |= 1;
- break;
- case '*': /* remember ambiguous names */
- case '?':
- foundChars |= 2;
- break;
- case '/': /* remember where the real fn starts */
- case '\\': /* also don't remember dots in paths */
- case ':':
- fn2 = fn1;
- foundChars &= ~1;
- break;
- }
- }
- *fn1 = 0; /* null terminate it */
-
- /* if no wildcards, tack on a star, or a star dot star */
- if (foundChars == 1) strcat(findname, "*");
- else if (foundChars == 0) strcat(findname, "*.*");
-
- oldDta = getdta();
- if (foundChars & 2) {
- j = oldCur - cur; /* remove the word. */
- while (j--) delchr();
-
- if (!findfirst(findname, &ourFF, FA_DIREC)) {
- do {
- copyFn(findname, fn2, &ourFF.ff_name);
- insprintable(' ');
- } while (!findnext(&ourFF));
- }
- } else {
- if (expandFilename(findname, fn2)) { /* only if a filename was found. */
-
- j = oldCur - cur; /* remove the word. */
- while (j--) delchr();
-
- copyFn(findname, fn2, fn2); /* our filename starts here */
- }
- showln();
- setdta(oldDta);
- }
- }
-
-
- copyFn(char *findname, char *fn2, char *fn)
- {
- char *fn1;
-
- while (findname != fn2) insprintable(*findname++);
-
- while (*fn != '\0') insprintable(tolower(*fn++));
- }
-
-
- int expandFilename(char *findname, char *fn2)
- {
- struct ffblk ourFF;
- char *fn0, *fn1;
-
- if (findfirst(findname, &ourFF, FA_DIREC)) { /* no files match */
- bell();
- return (FALSE);
- } else { /* at least one file */
- strcpy(fn2, &ourFF.ff_name);
- if (ourFF.ff_attrib & FA_DIREC) strcat(fn2, "\\");
- if (findnext(&ourFF)) return (TRUE); /* one file matches */
- else {
- do {
- fn0 = fn2;
- fn1 = ourFF.ff_name;
- while (*fn0++ != '\0') {
- if (fn0[-1] != *fn1++) break;
- }
- fn0[-1] = 0;
- } while (!findnext(&ourFF));
- bell();
- return (TRUE);
- }
- }
- }
-
-
- /* put character to console, converting controls to printables */
- pctl(int c)
- {
- if (c == DEL)
- {
- pc('^');
- pc('?');
- return;
- }
-
- if (c < ' ')
- {
- pc('^');
- pc(c + '@');
- return;
- }
-
- pc(c);
- }
-
- /* initialize positions */
- init_pos(void)
- {
- prevpos = endpos = (startpos = getpos()) & 0xff00;
- }
-
- /* put character to console */
- pc(int c)
- {
- unsigned pos;
-
- putch(c);
- pos = getpos();
- if (pos == endpos && prevpos > endpos)
- startpos -= 0x0100;
- else
- if ((pos & 0x00ff) == 0 & pos > endpos)
- endpos = pos;
- prevpos = pos;
- }
-
- /* audible alarm */
- bell(void)
- {
- putch(BEL);
- }
-
- /* put a character to the screen */
- putch(char ch)
- {
- _DL = ch;
- _AH = 2;
- geninterrupt(0x21);
- }
-
- /* get various screen & cursor characteristics */
- getvpage(void)
- {
- struct REGS r;
-
- r.x.ax = 0x0f00;
- int86(0x10, &r, &r);
- vpage = r.x.bx;
- maxcols = r.x.ax >> 8;
-
- r.x.ax = 0x0300;
- int86(0x10, &r, &r);
- cursor = r.x.cx;
- icursor = (((cursor & 0xff) - 4) << 8) + (cursor & 0xff);
- }
-
- /* get current screen position */
- getpos(void)
- {
- struct REGS r;
-
- r.x.ax = 0x0300;
- r.x.bx = vpage;
- int86(0x10, &r, &r);
- return r.x.dx;
- }
-
- /* set screen position */
- setpos(p)
- unsigned p;
- {
- struct REGS r;
-
- r.x.ax = 0x0200;
- r.x.bx = vpage;
- r.x.dx = p;
- int86(0x10, &r, &r);
- prevpos = p;
- }
-
- /* set cursor type */
- setcursor(unsigned c)
- {
- struct REGS r;
-
- r.x.ax = 0x0100;
- r.x.cx = c;
- int86(0x10, &r, &r);
- }